home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyc (Python 2.6) import cups from cupshelpers import parseDeviceID import string import locale import os.path as os import re from import _debugprint __all__ = [ 'ppdMakeModelSplit', 'PPDs'] def ppdMakeModelSplit(ppd_make_and_model): ''' Split a ppd-make-and-model string into a canonical make and model pair. @type ppd_make_and_model: string @param ppd_make_and_model: IPP ppd-make-and-model attribute @return: a string pair representing the make and the model ''' if re.search('^\\s*(deskjet|dj\x08|dj\\d|laserjet|lj\x08|color\\s*laserjet|color\\s*lj\x08|designjet|officejet|oj\x08|photosmart|ps\x08|psc)', ppd_make_and_model, re.I) or re.search('(edgeline)', ppd_make_and_model, re.I): make = 'HP' model = ppd_make_and_model elif re.search('^\\s*(stylus|aculaser)', ppd_make_and_model, re.I): make = 'Epson' model = ppd_make_and_model elif re.search('^\\s*(stylewriter|imagewriter|deskwriter|laserwriter)', ppd_make_and_model, re.I): make = 'Apple' model = ppd_make_and_model elif re.search('^\\s*(pixus|pixma|selphy|imagerunner|\x08bjc\x08|\x08bj\x08|\x08lbp\x08)', ppd_make_and_model, re.I): make = 'Canon' model = ppd_make_and_model elif re.search('^\\s*(\x08hl\x08|\x08dcp\x08|\x08mfc\x08)', ppd_make_and_model, re.I): make = 'Brother' model = ppd_make_and_model elif re.search('^\\s*(docuprint|docupage|phaser|workcentre|homecentre)', ppd_make_and_model, re.I): make = 'Xerox' model = ppd_make_and_model elif re.search('^\\s*(optra|(color\\s*|)jetprinter)', ppd_make_and_model, re.I): make = 'Lexmark' model = ppd_make_and_model elif re.search('^\\s*(magicolor|pageworks|pagepro)', ppd_make_and_model, re.I): make = 'KONICA MINOLTA' model = ppd_make_and_model elif re.search('^\\s*(aficio)', ppd_make_and_model, re.I): make = 'Ricoh' model = ppd_make_and_model elif re.search('^\\s*(varioprint)', ppd_make_and_model, re.I): make = 'Oce' model = ppd_make_and_model elif re.search('^\\s*(okipage|microline)', ppd_make_and_model, re.I): make = 'Oki' model = ppd_make_and_model elif re.search('^\\s*(konica[\\s_-]*minolta)', ppd_make_and_model, re.I): make = 'KONICA MINOLTA' model = ppd_make_and_model model = re.sub('(?i)KONICA[\\s_-]*MINOLTA\\s*', '', model, 1) elif re.search('turboprint', ppd_make_and_model, re.I): t = ppd_make_and_model.find(' TurboPrint') if t != -1: ppd_make_and_model = ppd_make_and_model[:t] try: (make, model) = ppd_make_and_model.split('_', 1) except: make = ppd_make_and_model model = '' make = re.sub('(?<=[a-z])(?=[0-9])', ' ', make) make = re.sub('(?<=[a-z])(?=[A-Z])', ' ', make) model = re.sub('(?<=[a-z])(?=[0-9])', ' ', model) model = re.sub('(?<=[a-z])(?=[A-Z])', ' ', model) model = re.sub(' Jet', 'Jet', model) model = re.sub('Photo Smart', 'PhotoSmart', model) else: try: (make, model) = ppd_make_and_model.split(' ', 1) except: make = ppd_make_and_model model = '' def strip_suffix(model, suffix): if model.endswith(suffix): return model[:-len(suffix)] return model c = model.find(',') if c != -1: model = model[:c] v = model.find(' v') if v != -1: if (model[v + 2].isdigit() or model[v + 2] == '.') and model[v + 3].isdigit(): model = model[:v] h = model.find(' hpijs') if h != -1: model = model[:h] f = model.find(' Foomatic/') if f != -1: model = model[:f] gutenprint = model.find(' - CUPS+Gutenprint') if gutenprint != -1: model = model[:gutenprint] gimpprint = model.find(' - CUPS+Gimp-Print') if gimpprint != -1: model = model[:gimpprint] wth = model.find(' w/') if wth != -1: model = model[:wth] make = re.sub('(?i)KONICA[\\s_-]*MINOLTA', 'KONICA MINOLTA', make, 1) make = re.sub('(?i)HEWLETT[\\s_-]PACKARD', 'HP', make, 1) make = re.sub('(?i)Lexmark\\s*International', 'Lexmark', make, 1) model = re.sub('(?i)\\s*\\(recommended\\)', '', model) model = re.sub('(?i)\\s*-\\s*PostScript\\b', '', model) model = re.sub('(?i)\\s*\\bseries\\b', '', model) if make.lower() == 'hp': model = re.sub('(?i)^dj\\b', 'DeskJet', model) model = re.sub('(?i)^LJ\\b', 'LaserJet', model) model = re.sub('(?i)^OJ\\b', 'OfficeJet', model) model = re.sub('(?i)^Color\\s*LJ\\b', 'Color LaserJet', model) model = re.sub('(?i)^PS\\b', 'PhotoSmart', model) model = re.sub('(?i)\\s*\\bPS[123]?\\b', '', model) model = re.sub('(?i)\\s*\\bPXL', '', model) model = re.sub('(?i)[\\s_-]+BT\\b', '', model) model = re.sub('(?i)\\s*\\(Bluetooth\\)', '', model) model = re.sub('(?i)\\s*-\\s*(RC|Ver(|sion))\\s*-*\\s*[0-9\\.]+', '', model) model = re.sub('(?i)\\s*-\\s*(RC|Ver(|sion))\\b', '', model) model = re.sub('(?i)\\s*PostScript\\s*$', '', model) model = re.sub('(?i)\\s*\\(\\s*\\)', '', model) model = re.sub('(?i)\\s*[\\-\\/]\\s*$', '', model) for mfr in [ 'Apple', 'Canon', 'Epson', 'Lexmark', 'Oki']: if make == mfr.upper(): make = mfr continue model = model.strip() return (make, model) DRIVER_TYPE_DOWNLOADED_NOW = 5 DRIVER_TYPE_FOOMATIC_RECOMMENDED_NON_POSTSCRIPT = 8 DRIVER_TYPE_VENDOR = 10 DRIVER_TYPE_FOOMATIC_RECOMMENDED_POSTSCRIPT = 15 DRIVER_TYPE_FOOMATIC_HPIJS_ON_HP = 17 DRIVER_TYPE_GUTENPRINT_NATIVE_SIMPLIFIED = 20 DRIVER_TYPE_GUTENPRINT_NATIVE = 25 DRIVER_TYPE_SPLIX = 27 DRIVER_TYPE_FOOMATIC_PS = 30 DRIVER_TYPE_FOOMATIC_HPIJS = 40 DRIVER_TYPE_FOOMATIC_GUTENPRINT_SIMPLIFIED = 50 DRIVER_TYPE_FOOMATIC_GUTENPRINT = 60 DRIVER_TYPE_FOOMATIC = 70 DRIVER_TYPE_CUPS = 80 DRIVER_TYPE_FOOMATIC_GENERIC = 90 DRIVER_TYPE_3RD_PARTY_NONFREE = 95 DRIVER_DOES_NOT_WORK = 999 def _getDriverType(ppdname, ppds = None): '''Decides which of the above types ppdname is.''' if ppdname.find('turboprint') != -1: return DRIVER_TYPE_3RD_PARTY_NONFREE if ppdname.find('gutenprint') != -1: if ppdname.find('/simple/') != -1 or ppdname.find('.sim-') != -1: return DRIVER_TYPE_GUTENPRINT_NATIVE_SIMPLIFIED return DRIVER_TYPE_GUTENPRINT_NATIVE ppdname.find('gutenprint') != -1 if ppdname.find('splix') != -1: return DRIVER_TYPE_SPLIX if ppdname.find(':') == -1 and ppdname.find('/cups-included/') != -1: return DRIVER_TYPE_CUPS if ppdname.startswith('foomatic:'): if ppdname.find('Generic') != -1: return DRIVER_TYPE_FOOMATIC_GENERIC if ppds != None and ppds.getInfoFromPPDName(ppdname).get('ppd-make-and-model', '').find('(recommended)') != -1: if ppds.getInfoFromPPDName(ppdname).get('ppd-make-and-model', '').find('Postscript') != -1: return DRIVER_TYPE_FOOMATIC_RECOMMENDED_POSTSCRIPT return DRIVER_TYPE_FOOMATIC_RECOMMENDED_NON_POSTSCRIPT ppds.getInfoFromPPDName(ppdname).get('ppd-make-and-model', '').find('(recommended)') != -1 if ppdname.find('-Postscript') != -1: return DRIVER_TYPE_FOOMATIC_PS if ppdname.find('-gutenprint') != -1: if ppdname.find('-simplified') != -1: return DRIVER_TYPE_FOOMATIC_GUTENPRINT_SIMPLIFIED return DRIVER_TYPE_FOOMATIC_GUTENPRINT return DRIVER_TYPE_FOOMATIC return DRIVER_TYPE_VENDOR class PPDs: ''' This class is for handling the list of PPDs returned by CUPS. It indexes by PPD name and device ID, filters by natural language so that foreign-language PPDs are not included, and sorts by driver type. If an exactly-matching PPD is not available, it can substitute with a PPD for a similar model or for a generic driver. ''' STATUS_SUCCESS = 0 STATUS_MODEL_MISMATCH = 1 STATUS_GENERIC_DRIVER = 2 STATUS_NO_DRIVER = 3 def __init__(self, ppds, language = None): ''' @type ppds: dict @param ppds: dict of PPDs as returned by cups.Connection.getPPDs() @type language: string \t@param language: language name, as given by the first element of the pair returned by locale.getlocale() ''' self.ppds = ppds.copy() self.makes = None self.ids = None if language == None and language == 'C' or language == 'POSIX': language = 'en_US' u = language.find('_') if u != -1: short_language = language[:u] else: short_language = language to_remove = [] for ppdname, ppddict in self.ppds.iteritems(): try: natural_language = ppddict['ppd-natural-language'] except KeyError: continue if natural_language == 'en': continue if natural_language == language: continue if natural_language == short_language: continue to_remove.append(ppdname) for ppdname in to_remove: del self.ppds[ppdname] if self.ppds.has_key('raw'): makemodel = self.ppds['raw']['ppd-make-and-model'] if not makemodel.startswith('Generic '): self.ppds['raw']['ppd-make-and-model'] = 'Generic ' + makemodel def getMakes(self): ''' \t@returns: a list of strings representing makes, sorted according to the current locale \t''' self._init_makes() makes_list = self.makes.keys() makes_list.sort(locale.strcoll) try: makes_list.remove('Generic') makes_list.insert(0, 'Generic') except ValueError: pass return makes_list def getModels(self, make): ''' \t@returns: a list of strings representing models, sorted using \tcups.modelSort() \t''' self._init_makes() try: models_list = self.makes[make].keys() except KeyError: return [] models_list.sort(key = unicode.lower, cmp = cups.modelSort) return models_list def getInfoFromModel(self, make, model): ''' \tObtain a list of PPDs that are suitable for use with a particular printer model, given its make and model name. \t@returns: a dict, indexed by ppd-name, of dicts representing PPDs (as given by cups.Connection.getPPDs) \t''' self._init_makes() try: return self.makes[make][model] except KeyError: return { } def getInfoFromPPDName(self, ppdname): ''' \t@returns: a dict representing a PPD, as given by \tcups.Connection.getPPDs \t''' return self.ppds[ppdname] def orderPPDNamesByPreference(self, ppdnamelist = [], downloadedfiles = []): ''' \tSort a list of PPD names by (hard-coded) preferred driver \ttype. \t@param ppdnamelist: PPD names \t@type ppdnamelist: string list \t@returns: string list \t''' if len(ppdnamelist) < 1: return ppdnamelist dict = self.getInfoFromPPDName(ppdnamelist[0]) make_model = dict['ppd-make-and-model'] (mfg, mdl) = ppdMakeModelSplit(make_model) def getDriverTypeWithBias(x, mfg): t = _getDriverType(x, ppds = self) for file in downloadedfiles: (path, slash, filename) = file.rpartition('/') (xpath, xslash, xfilename) = x.rpartition('/') if filename == xfilename: return DRIVER_TYPE_DOWNLOADED_NOW if mfg == 'HP': if t == DRIVER_TYPE_FOOMATIC_HPIJS: t = DRIVER_TYPE_FOOMATIC_HPIJS_ON_HP if re.search('(?i)HP[-_]LaserJet_1[23]\\d\\d', x): t = DRIVER_TYPE_FOOMATIC_RECOMMENDED_NON_POSTSCRIPT return t def sort_ppdnames(a, b): ta = getDriverTypeWithBias(a, mfg) tb = getDriverTypeWithBias(b, mfg) if ta != tb: if tb < ta: return 1 return -1 ta != tb def is_C_locale(x): try: while x: i = x.find('C') if i == -1: return False lword = False if i == 0: lword = True elif x[i - 1] not in string.letters: lword = True if lword: rword = False if i == len(x) - 1: rword = True elif x[i + 1] not in string.letters: rword = True if rword: return True x = x[i + 1:] except UnicodeDecodeError: return False ca = is_C_locale(a) cb = is_C_locale(b) if ca != cb: if ca: l = a.find('C') else: l = b.find('C') if a[:l] == b[:l]: if cb: return 1 return -1 a[:l] == b[:l] if a > b: return 1 if a < b: return -1 return 0 ppdnamelist.sort(sort_ppdnames) return ppdnamelist def getPPDNameFromDeviceID(self, mfg, mdl, description = '', commandsets = [], uri = None, downloadedfiles = []): ''' \tObtain a best-effort PPD match for an IEEE 1284 Device ID. \tThe status is one of: \t - L{STATUS_SUCCESS}: the match was successful, and an exact match was found \t - L{STATUS_MODEL_MISMATCH}: a similar match was found, but the model name does not exactly match \t - L{STATUS_GENERIC_DRIVER}: no match was found, but a generic driver is available that can drive this device according to its command set list \t - L{STATUS_NO_DRIVER}: no match was found at all, and the returned PPD name is a last resort \t@param mfg: MFG or MANUFACTURER field \t@type mfg: string \t@param mdl: MDL or MODEL field \t@type mdl: string \t@param description: DES or DESCRIPTION field, optional \t@type description: string \t@param commandsets: CMD or COMMANDSET field, optional \t@type commandsets: string \t@param uri: device URI, optional (only needed for debugging) \t@type uri: string \t@returns: an integer,string pair of (status,ppd-name) \t''' _debugprint('\n%s %s' % (mfg, mdl)) self._init_ids() if mfg.lower() == 'hewlett-packard': mfg = 'HP' ppdnamelist = [] id_matched = False try: ppdnamelist = self.ids[mfg.lower()][mdl.lower()] status = self.STATUS_SUCCESS id_matched = True except KeyError: pass if mfg.lower() == 'hp': try: ppdnamelist += self.ids['hp'][mdl.lower()] status = self.STATUS_SUCCESS id_matched = True except KeyError: pass try: ppdnamelist += self.ids['hp'][mdl.lower().replace(' ', '_')] status = self.STATUS_SUCCESS id_matched = True except KeyError: pass except: None<EXCEPTION MATCH>KeyError None<EXCEPTION MATCH>KeyError if mfg.lower() == 'apollo': try: ppdnamelist += self.ids['apollo'][mdl.lower()] status = self.STATUS_SUCCESS id_matched = True except KeyError: pass try: ppdnamelist += self.ids['apollo'][mdl.lower().replace(' ', '_')] status = self.STATUS_SUCCESS id_matched = True except KeyError: pass except: None<EXCEPTION MATCH>KeyError None<EXCEPTION MATCH>KeyError _debugprint('Trying make/model names') mfgl = mfg.lower() mdls = None self._init_makes() for attempt in range(2): for make, models in self.makes.iteritems(): if make.lower() == mfgl: mdls = models break continue if mfgl == 'hewlett-packard': mfgl = 'hp' continue if mfgl == 'lexmark international': mfgl = 'lexmark' continue if mfgl == '': (tmp1, tmp2) = ppdMakeModelSplit(mdl) mfgl = tmp1.lower() continue ppdnamelist2 = None if mdl.startswith(mfg + ' '): mdl = mdl[len(mfg) + 1:] if mdl.startswith('Hewlett-Packard '): mdl = mdl[16:] if mdl.startswith('HP '): mdl = mdl[3:] if mdls: for model, ppdnames in mdls.iteritems(): if model.lower() == mdl.lower(): ppdnamelist2 = ppdnames.keys() status = self.STATUS_SUCCESS break continue if not ppdnamelist2: (mfg2, mdl2) = ppdMakeModelSplit(mfg + ' ' + mdl) for model, ppdnames in mdls.iteritems(): if model.lower() == mdl2.lower(): ppdnamelist2 = ppdnames.keys() status = self.STATUS_SUCCESS break continue if ppdnamelist: if ppdnamelist2: ppdnamelist = ppdnamelist + ppdnamelist2 elif ppdnamelist2: ppdnamelist = ppdnamelist2 if not ppdnamelist and mdls: (s, ppds) = self._findBestMatchPPDs(mdls, mdl) if s != self.STATUS_NO_DRIVER: status = s ppdnamelist = ppds if not ppdnamelist and commandsets: if type(commandsets) != list: commandsets = commandsets.split(',') generic = self._getPPDNameFromCommandSet(commandsets) if generic: status = self.STATUS_GENERIC_DRIVER ppdnamelist = generic if not ppdnamelist: _debugprint('Text-only fallback') status = self.STATUS_NO_DRIVER ppdnamelist = [ 'textonly.ppd'] tppdfound = 0 for ppdpath in self.ppds.keys(): if ppdpath.endswith(ppdnamelist[0]): tppdfound = 1 ppdnamelist = [ ppdpath] break continue if tppdfound == 0: _debugprint('No text-only driver?! Using postscript.ppd') ppdnamelist = [ 'postscript.ppd'] psppdfound = 0 for ppdpath in self.ppds.keys(): if ppdpath.endswith(ppdnamelist[0]): psppdfound = 1 ppdnamelist = [ ppdpath] break continue if psppdfound == 0: _debugprint('No postscript.ppd; choosing any') ppdnamelist = [ self.ppds.keys()[0]] if id_matched: _debugprint('Checking DES field') inexact = set() if description: for ppdname in ppdnamelist: if ppdname.find('hpijs'): continue ppddict = self.ppds[ppdname] id = ppddict['ppd-device-id'] if not id: continue id_dict = parseDeviceID(id) if id_dict['DES'] != description: inexact.add(ppdname) continue exact = set(ppdnamelist).difference(inexact) _debugprint('discarding: %s' % inexact) if len(exact) >= 1: ppdnamelist = list(exact) ppdnamelist = self.orderPPDNamesByPreference(ppdnamelist, downloadedfiles) _debugprint('Found PPDs: %s' % str(ppdnamelist)) if not id_matched: sanitised_uri = re.sub(pattern = '//[^@]*@/?', repl = '//', string = str(uri)) print 'No ID match for device %s:' % sanitised_uri print ' <manufacturer>%s</manufacturer>' % mfg print ' <model>%s</model>' % mdl print ' <description>%s</description>' % description try: cmd = reduce((lambda x, y: x + ',' + y), commandsets) except TypeError: cmd = '' print ' <commandset>%s</commandset>' % cmd print 'Using %s' % ppdnamelist[0] return (status, ppdnamelist[0]) def _findBestMatchPPDs(self, mdls, mdl): ''' Find the best-matching PPDs based on the MDL Device ID. This function could be made a lot smarter. ''' _debugprint('Trying best match') mdll = mdl.lower() if mdll.endswith(' series'): mdll = mdll[:-7] mdl = mdl[:-7] best_mdl = None best_matchlen = 0 mdlnames = mdls.keys() mdlnamesl = map((lambda x: (x, x.lower())), mdlnames) mdlnamesl.append((mdl, mdll)) mdlnamesl.sort((lambda x, y: cups.modelSort(x[1], y[1]))) i = mdlnamesl.index((mdl, mdll)) candidates = [ mdlnamesl[i - 1]] if i + 1 < len(mdlnamesl): candidates.append(mdlnamesl[i + 1]) _debugprint(candidates[0][0] + ' <= ' + mdl + ' <= ' + candidates[1][0]) else: _debugprint(candidates[0][0] + ' <= ' + mdl) for candidate, candidatel in candidates: prefix = os.path.commonprefix([ candidatel, mdll]) if len(prefix) > best_matchlen: best_mdl = mdls[candidate].keys() best_matchlen = len(prefix) _debugprint('%s: match length %d' % (candidate, best_matchlen)) continue if best_mdl and best_matchlen > len(mdll) / 2: ppdnamelist = best_mdl if best_matchlen == len(mdll): status = self.STATUS_SUCCESS else: status = self.STATUS_MODEL_MISMATCH else: status = self.STATUS_NO_DRIVER ppdnamelist = None mdlnames.sort(cups.modelSort) mdlitems = (map,)((lambda x: (x.lower(), mdls[x])), mdlnames) modelid = None for word in mdll.split(' '): if modelid == None: modelid = word have_digits = False for i in range(len(word)): if word[i].isdigit(): have_digits = True break continue if have_digits: modelid = word break continue digits = 0 digits_start = -1 digits_end = -1 for i in range(len(modelid)): if modelid[i].isdigit(): if digits_start == -1: digits_start = i digits_end = i digits += 1 continue if digits_start != -1: break continue digits_end += 1 modelnumber = 0 if digits > 0: modelnumber = int(modelid[digits_start:digits_end]) modelpattern = modelid[:digits_start] + '%d' + modelid[digits_end:] _debugprint("Searching for model ID '%s', '%s' %% %d" % (modelid, modelpattern, modelnumber)) ignore_digits = 0 best_mdl = None found = False while ignore_digits < digits: div = pow(10, ignore_digits) modelid = modelpattern % (modelnumber / div) * div _debugprint('Ignoring %d of %d digits, trying %s' % (ignore_digits, digits, modelid)) for name, ppds in mdlitems: for word in name.split(' '): if word.lower() == modelid: found = True break continue if found: best_mdl = ppds.keys() break continue if found: break ignore_digits += 1 if digits < 2: break continue if found: ppdnamelist = best_mdl status = self.STATUS_MODEL_MISMATCH return (status, ppdnamelist) def _getPPDNameFromCommandSet(self, commandsets = []): '''Return ppd-name list or None, given a list of strings representing the command sets supported.''' try: self._init_makes() models = self.makes['Generic'] except KeyError: return None def get(*candidates): for model in candidates: (s, ppds) = self._findBestMatchPPDs(models, model) if s == self.STATUS_SUCCESS: return ppds cmdsets = map((lambda x: x.lower()), commandsets) if 'postscript' in cmdsets and 'postscript2' in cmdsets or 'postscript level 2 emulation' in cmdsets: return get('PostScript Printer') if 'pclxl' in cmdsets and 'pcl-xl' in cmdsets and 'pcl6' in cmdsets or 'pcl 6 emulation' in cmdsets: return get('PCL 6/PCL XL Printer') if 'pcl5e' in cmdsets: return get('PCL 5e Printer') if 'pcl5c' in cmdsets: return get('PCL 5c Printer') if 'pcl5' in cmdsets or 'pcl 5 emulation' in cmdsets: return get('PCL 5 Printer') if 'pcl' in cmdsets: return get('PCL 3 Printer') if 'escpl2' in cmdsets and 'esc/p2' in cmdsets or 'escp2e' in cmdsets: return get('ESC/P Dot Matrix Printer') def _init_makes(self): if self.makes: return None makes = { } lmakes = { } lmodels = { } for ppdname, ppddict in self.ppds.iteritems(): ppd_make_and_model = ppddict['ppd-make-and-model'] (make, model) = ppdMakeModelSplit(ppd_make_and_model) lmake = make.lower() lmodel = model.lower() if not lmakes.has_key(lmake): lmakes[lmake] = make lmodels[lmake] = { } makes[make] = { } else: make = lmakes[lmake] if not lmodels[lmake].has_key(lmodel): lmodels[lmake][lmodel] = model makes[make][model] = { } else: model = lmodels[lmake][lmodel] makes[make][model][ppdname] = ppddict self.makes = makes self.lmakes = lmakes self.lmodels = lmodels def _init_ids(self): if self.ids: return None ids = { } for ppdname, ppddict in self.ppds.iteritems(): if not ppddict.has_key('ppd-device-id'): continue id = ppddict['ppd-device-id'] if not id: continue v = id.find(':Model') if v != -1: id = id[:v] + ';' + id[v + 1:] id_dict = parseDeviceID(id) lmfg = id_dict['MFG'].lower() lmdl = id_dict['MDL'].lower() if lmfg == 'hewlett-packard': lmfg = 'hp' bad = False if len(lmfg) == 0: _debugprint('Missing MFG field for %s' % ppdname) bad = True if len(lmdl) == 0: _debugprint('Missing MDL field for %s' % ppdname) bad = True if bad: continue if not ids.has_key(lmfg): ids[lmfg] = { } if not ids[lmfg].has_key(lmdl): ids[lmfg][lmdl] = [] ids[lmfg][lmdl].append(ppdname) self.ids = ids def _show_help(): print 'usage: ppds.py [--deviceid] [--list-models] [--list-ids] [--debug]' def _self_test(argv): import sys import getopt try: (opts, args) = getopt.gnu_getopt(argv[1:], '', [ 'help', 'deviceid', 'list-models', 'list-ids', 'debug']) except getopt.GetoptError: _show_help() sys.exit(1) stdin_deviceid = False list_models = False list_ids = False for opt, optarg in opts: if opt == '--help': show_help() sys.exit(0) if opt == '--deviceid': stdin_deviceid = True continue if opt == '--list-models': list_models = True continue if opt == '--list-ids': list_ids = True continue picklefile = 'pickled-ppds' import pickle try: f = open(picklefile, 'r') cupsppds = pickle.load(f) except IOError: f = open(picklefile, 'w') c = cups.Connection() cupsppds = c.getPPDs() pickle.dump(cupsppds, f) ppds = PPDs(cupsppds) makes = ppds.getMakes() models_count = 0 for make in makes: models = ppds.getModels(make) models_count += len(models) if list_models: print make for model in models: print ' ' + model print '%d makes, %d models' % (len(makes), models_count) ppds.getPPDNameFromDeviceID('HP', 'PSC 2200 Series') makes = ppds.ids.keys() models_count = 0 for make in makes: models = ppds.ids[make] models_count += len(models) if list_ids: print make for model in models: print ' %s (%d)' % (model, len(ppds.ids[make][model])) for driver in ppds.ids[make][model]: print ' ' + driver print '%d ID makes, %d ID models' % (len(makes), models_count) print '\nID matching tests\n' idlist = [ ('MFG:EPSON;CMD:ESCPL2,BDC,D4,D4PX;MDL:Stylus D78;CLS:PRINTER;DES:EPSON Stylus D78;', 1, 'Epson Stylus D68'), ('MFG:Hewlett-Packard;MDL:LaserJet 1200 Series;CMD:MLC,PCL,POSTSCRIPT;CLS:PRINTER;', 0, 'HP LaserJet 1200'), ('MFG:Hewlett-Packard;MDL:LaserJet 3390 Series;CMD:MLC,PCL,POSTSCRIPT;CLS:PRINTER;', 0, 'HP LaserJet 3390'), ('MFG:Hewlett-Packard;MDL:PSC 2200 Series;CMD:MLC,PCL,PML,DW-PCL,DYN;CLS:PRINTER;1284.4DL:4d,4e,1;', 0, 'HP PSC 2210'), ('MFG:HP;MDL:PSC 2200 Series;CLS:PRINTER;DES:PSC 2200 Series;', 1, 'HP PSC 2210'), ('MFG:HEWLETT-PACKARD;MDL:DESKJET 990C;CMD:MLC,PCL,PML;CLS:PRINTER;DES:Hewlett-Packard DeskJet 990C;', 0, 'HP DeskJet 990C'), ('CLASS:PRINTER;MODEL:HP LaserJet 6MP;MANUFACTURER:Hewlett-Packard;DESCRIPTION:Hewlett-Packard LaserJet 6MP Printer;COMMAND SET:PJL,MLC,PCLXL,PCL,POSTSCRIPT;', 0, 'HP LaserJet 6MP'), ('MFG:Canon;CMD:BJL,BJRaster3,BSCCe;SOJ:TXT01;MDL:iP3000;CLS:PRINTER;DES:Canon iP3000;VER:1.09;STA:10;FSI:03;', 1, 'Canon PIXMA iP3000'), ('MFG:HP;MDL:Deskjet 5400 series;CMD:MLC,PCL,PML,DW-PCL,DESKJET,DYN;1284.4DL:4d,4e,1;CLS:PRINTER;DES:5440;', 1, 'HP DeskJet 5440'), ('MFG:Hewlett-Packard;MDL:HP LaserJet 3390;CMD:PJL,MLC,PCL,POSTSCRIPT,PCLXL;', 0, 'HP LaserJet 3390.*Postscript'), ('MFG:New;MDL:Unknown PS Printer;CMD:POSTSCRIPT;', 2, 'Generic postscript printer'), ('MFG:New;MDL:Unknown PCL6 Printer;CMD:PCLXL;', 2, 'Generic PCL 6'), ('MFG:New;MDL:Unknown PCL5e Printer;CMD:PCL5e;', 2, 'Generic PCL 5e'), ('MFG:New;MDL:Unknown PCL5c Printer;CMD:PCL5c;', 2, 'Generic PCL 5c'), ('MFG:New;MDL:Unknown PCL5 Printer;CMD:PCL5;', 2, 'Generic PCL 5'), ('MFG:New;MDL:Unknown PCL3 Printer;CMD:PCL;', 2, 'Generic PCL'), ('MFG:New;MDL:Unknown ESC/P Printer;CMD:ESCP2E;', 2, 'Generic ESC/P'), ('MFG:New;MDL:Unknown Printer;', 100, None)] if stdin_deviceid: idlist = [ (raw_input('Device ID: '), 2, '')] all_passed = True for id, max_status_code, modelre in idlist: id_dict = parseDeviceID(id) (status, ppdname) = ppds.getPPDNameFromDeviceID(id_dict['MFG'], id_dict['MDL'], id_dict['DES'], id_dict['CMD']) if status < max_status_code: success = True elif status == max_status_code: ppddict = ppds.getInfoFromPPDName(ppdname) match = re.match(modelre, ppddict['ppd-make-and-model'], re.I) success = match != None else: success = False if success: result = 'PASS' else: result = '*** FAIL ***' print '%s: %s %s' % (result, id_dict['MFG'], id_dict['MDL']) if all_passed: pass all_passed = success if not all_passed: raise RuntimeError all_passed